#include "EntityManager.h"
#include <cmath>
#include "Terrain.h"
#include "BaseEntity.h"
#include "GlobalDefines.h"
#include ".\gameobject.h"
#include ".\Model.h"
#include "Player.h"
#include "DebugGrid.h"
#include "Enemy.h"
#include "telegram.h"
#include "MessageHandler.h"

float delta_t = 0, acum = 0, dly_time = 2;
float d_Time = 0, alator = 0, delay = 6;
float posDist, radDist;

EntityManager::EntityManager()
{
	m_player = NULL;
	m_enemy1 = NULL;
	m_enemy2 = NULL;
	m_enemy3 = NULL;
	m_enemy4 = NULL;
}

EntityManager::~EntityManager()
{

}

EntityManager* EntityManager::Instance()
{
  static EntityManager instance;

  return &instance;
}

GameObject* EntityManager::GetEntityFromID(int id)
{
	return objects[id];
}

void EntityManager::update(float a_dt)
{
	m_dt = a_dt;
	for (unsigned int i=0; i<objects.size(); i++)
	{
		objects[i]->update(a_dt);
	}
	collision();	
	projectileSystem();
	chargeOk();
}

void EntityManager::draw()
{
	LPDIRECT3DDEVICE9 device=dxMgr.getDevice();
	for (unsigned int i=0; i<objects.size(); i++)
	{
		dxMgr.MatrixStack->Push();
		static DWORD lastTime = timeGetTime();

		float timeElapsed = 0.001f*(timeGetTime()-lastTime);
		lastTime = timeGetTime();

		D3DXMATRIX		transMatrix;				
		D3DXMATRIX		rotationMatrix;
		D3DXMATRIX		scaleMatrix;

		//set the scale matrix
		D3DXMatrixScaling(&scaleMatrix, objects[i]->getSize(), objects[i]->getSize(), objects[i]->getSize());

		// store the m_position information into the translation matrix
		D3DXMatrixTranslation(&transMatrix, objects[i]->getXPosition(),
											objects[i]->getYPosition(), 
											objects[i]->getZPosition());

		// set the rotation matrix
		D3DXMatrixRotationYawPitchRoll(&rotationMatrix, D3DXToRadian(objects[i]->getYRotation()),
														D3DXToRadian(objects[i]->getXRotation()),
														D3DXToRadian(objects[i]->getZRotation()));

		// Multiply the translation matrix by the rotation matrix, store the result 
		//in the translation matrix
		D3DXMatrixMultiply(&transMatrix, &rotationMatrix, &transMatrix);
	    
		// Multiply the translation matrix by the scale matrix, store the result in    
		//the translation matrix
		D3DXMatrixMultiply(&transMatrix, &scaleMatrix, &transMatrix);
		
		dxMgr.MatrixStack->MultMatrixLocal(&transMatrix);
		// m_position the object for rendering based on the m_position, rotation and scaleing.
		device->SetTransform(D3DTS_WORLD, dxMgr.MatrixStack->GetTop());
		objects[i]->render(device);
		dxMgr.MatrixStack->Pop();
	}
}

void EntityManager::EntInput()
{
	m_player->PlayerInput();
}

float EntityManager::distFormula(D3DXVECTOR3 posit1, D3DXVECTOR3 posit2) 
{ 
	float distance; 
	distance=(sqrt(pow(posit1.x-posit2.x, 2)+ pow(posit1.y-posit2.y, 2)+ pow(posit1.z-posit2.z, 2)));

	return distance;
}

float EntityManager::sumRadius(float a_radius1, float a_radius2)
{
	float a_radiusTotal = a_radius1 + a_radius2;
	return a_radiusTotal;
}

bool EntityManager::createGameObjects()
{
	// Clear out the objects vector
	objects.clear();

	// create Objects
	createPlayer();
	createEnemy();

	// Create and turn on a directional light
	lightID=dxLtMgr.createDirectLight(dxMgr.getDevice(),
							  D3DXVECTOR3( 0.0f, 0.0f, -50.0f ),
							  D3DXVECTOR3( 0.3f, 0.0f, 1.0f ),
							  0.5f,
							  0.0f,
							  sqrtf(FLT_MAX));

	// Add to the objects vector structure
	objects.push_back((GameObject*)m_player);
	objects.push_back((GameObject*)m_enemy1);
	objects.push_back((GameObject*)m_enemy2);
	objects.push_back((GameObject*)m_enemy3);
	objects.push_back((GameObject*)m_enemy4);
	return true;
}

void EntityManager::createPlayer()
{
	m_player = new Player(0);
	m_player->create(dxMgr.getDevice(),"tiny.x");
	m_player->setVectorRotation(270,0,0);
	m_player->setDirection(1,0,1);
	m_player->setMagnitude(300.0,0.5,300.0);
	m_player->updateDelta();
	m_player->setPosition(0,0,0);
	m_player->rotateVector();
	m_player->setSize(0.3);
}
void EntityManager::createEnemy()
{
	m_enemy1 = new Enemy(1);
	m_enemy2 = new Enemy(2);
	m_enemy3 = new Enemy(3);
	m_enemy4 = new Enemy(4);

	// Init Objects
	m_enemy1->create(dxMgr.getDevice(),"tiny.x");
	m_enemy2->create(dxMgr.getDevice(),"tiny.x");
	m_enemy3->create(dxMgr.getDevice(),"tiny.x");
	m_enemy4->create(dxMgr.getDevice(),"tiny.x");

	// set objects positions
	m_enemy1->setPosition(1000, 0,0);
	m_enemy1->setVectorRotation(270,0,0);
	m_enemy1->setDirection(1,0,1);
	m_enemy1->setMagnitude(250.0,0.2,250.0);
	m_enemy1->updateDelta();
	m_enemy1->rotateVector();
	m_enemy1->setSize(0.3);

	// set objects positions
	m_enemy2->setPosition(-1000, 0,0);
	m_enemy2->setVectorRotation(270,0,0);
	m_enemy2->setDirection(1,0,1);
	m_enemy2->setMagnitude(250.0,0.2,250.0);
	m_enemy2->updateDelta();
	m_enemy2->rotateVector();
	m_enemy2->setSize(0.3);

	// set objects positions
	m_enemy3->setPosition(0,0,1000);
	m_enemy3->setVectorRotation(270,0,0);
	m_enemy3->setDirection(1,0,1);
	m_enemy3->setMagnitude(250.0,0.2,250.0);
	m_enemy3->updateDelta();
	m_enemy3->rotateVector();
	m_enemy3->setSize(0.3);

	// set objects positions
	m_enemy4->setPosition(-1000,0,1000);
	m_enemy4->setVectorRotation(270,0,0);
	m_enemy4->setDirection(1,0,1);
	m_enemy4->setMagnitude(250.0,0.2,250.0);
	m_enemy4->updateDelta();
	m_enemy4->rotateVector();
	m_enemy4->setSize(0.3);

}

void EntityManager::collision()
{
	// 1st Enemy
	m_enemy1->SetPlayerInfo(m_player->getPosition());

	float curDistance = distFormula(m_player->getPosition(),m_enemy1->getPosition());
	float minDistance = sumRadius(m_player->getRadius(),m_enemy1->getRadius());
	if(curDistance<=minDistance)
	{
		//m_player->revertToOld();
		Handler->SendMessage(0.0,//delay
							-1,//sender
							0,//reciever
							MSG_COLLIDE,//message 
							NULL);//extra info
		
		//m_enemy1->revertToOld();
		Handler->SendMessage(0.0,-1,1,MSG_COLLIDE,NULL);
	}

	minDistance = sumRadius(m_player->getRadius(), m_enemy1->GetRadarRad());
	if(curDistance<=minDistance)
	{
		Handler->SendMessage(0.0,-1,1,MSG_AWARE,NULL);
	}

	// Melee on enemy1
	minDistance = sumRadius(m_player->getMeleeRad(), m_enemy1->getRadius());
	if(curDistance<=minDistance)
	{
		m_player->combat1();
	}

	minDistance = sumRadius(m_player->getRadius(), m_enemy1->GetMeleeRad());
	if(curDistance<=minDistance)
	{
		m_enemy1->setRange(true);
	}
	else
	{
		m_enemy1->setRange(false);
	}

	// 2nd Enemy
	m_enemy2->SetPlayerInfo(m_player->getPosition());

	curDistance = distFormula(m_player->getPosition(),m_enemy2->getPosition());
	minDistance = sumRadius(m_player->getRadius(),m_enemy2->getRadius());
	if(curDistance<=minDistance)
	{
		//m_player->revertToOld();
		Handler->SendMessage(0.0,//delay
							-1,//sender
							0,//reciever
							MSG_COLLIDE,//message 
							NULL);//extra info
		//m_enemy1->revertToOld();
		Handler->SendMessage(0.0,-1,2,MSG_COLLIDE,NULL);
	}

	minDistance = sumRadius(m_player->getRadius(), m_enemy2->GetRadarRad());
	if(curDistance<=minDistance)
	{
		Handler->SendMessage(0.0,-1,2,MSG_AWARE,NULL);
	}

	// Melee on enemy2
	minDistance = sumRadius(m_player->getMeleeRad(), m_enemy2->getRadius());
	if(curDistance<=minDistance)
	{
		m_player->combat2();
	}

	minDistance = sumRadius(m_player->getRadius(), m_enemy2->GetMeleeRad());
	if(curDistance<=minDistance)
	{
		m_enemy2->setRange(true);
	}
	else
	{
		m_enemy2->setRange(false);
	}

	// 3rd Enemy
	m_enemy3->SetPlayerInfo(m_player->getPosition());

	curDistance = distFormula(m_player->getPosition(),m_enemy3->getPosition());
	minDistance = sumRadius(m_player->getRadius(),m_enemy3->getRadius());
	if(curDistance<=minDistance)
	{
		//m_player->revertToOld();
		Handler->SendMessage(0.0,//delay
							-1,//sender
							0,//reciever
							MSG_COLLIDE,//message 
							NULL);//extra info
		//m_enemy1->revertToOld();
		Handler->SendMessage(0.0,-1,3,MSG_COLLIDE,NULL);
	}

	minDistance = sumRadius(m_player->getRadius(), m_enemy3->GetRadarRad());
	if(curDistance<=minDistance)
	{
		Handler->SendMessage(0.0,-1,3,MSG_AWARE,NULL);
	}

	// Melee on 3rd enemy
	minDistance = sumRadius(m_player->getMeleeRad(), m_enemy3->getRadius());
	if(curDistance<=minDistance)
	{
		m_player->combat3();
	}

	minDistance = sumRadius(m_player->getRadius(), m_enemy3->GetMeleeRad());
	if(curDistance<=minDistance)
	{
		m_enemy3->setRange(true);
	}
	else
	{
		m_enemy3->setRange(false);
	}

	// 4th Enemy
	m_enemy4->SetPlayerInfo(m_player->getPosition());

	curDistance = distFormula(m_player->getPosition(),m_enemy4->getPosition());
	minDistance = sumRadius(m_player->getRadius(),m_enemy4->getRadius());
	if(curDistance<=minDistance)
	{
		//m_player->revertToOld();
		Handler->SendMessage(0.0,//delay
							-1,//sender
							0,//reciever
							MSG_COLLIDE,//message 
							NULL);//extra info
		//m_enemy1->revertToOld();
		Handler->SendMessage(0.0,-1,4,MSG_COLLIDE,NULL);
	}

	minDistance = sumRadius(m_player->getRadius(), m_enemy4->GetRadarRad());
	if(curDistance<=minDistance)
	{
		Handler->SendMessage(0.0,-1,4,MSG_AWARE,NULL);
	}

	// Melee on enemy2
	minDistance = sumRadius(m_player->getMeleeRad(), m_enemy4->getRadius());
	if(curDistance<=minDistance)
	{
		m_player->combat2();
	}

	minDistance = sumRadius(m_player->getRadius(), m_enemy4->GetMeleeRad());
	if(curDistance<=minDistance)
	{
		m_enemy4->setRange(true);
	}
	else
	{
		m_enemy4->setRange(false);
	}
}

void EntityManager::projectileSystem()
{
	if(m_player->isBallOn())
	{
		posDist = distFormula(m_player->getEballPos(),m_enemy1->getPosition());
		radDist = sumRadius(m_player->getEballRad(), m_enemy1->getRadius());
		if(posDist <= radDist)
		{
			Handler->SendMessage(0.0,0,1,MSG_ATK_AWR,NULL);
			m_player->EraseBall();
		}
	}

	if(m_player->isBallOn())
	{
		posDist = distFormula(m_player->getEballPos(),m_enemy2->getPosition());
		radDist = sumRadius(m_player->getEballRad(), m_enemy2->getRadius());
		if(posDist <= radDist)
		{
			Handler->SendMessage(0.0,0,2,MSG_ATK_AWR,NULL);
			m_player->EraseBall();
		}
	}

	if(m_player->isBallOn())
	{
		posDist = distFormula(m_player->getEballPos(),m_enemy3->getPosition());
		radDist = sumRadius(m_player->getEballRad(), m_enemy3->getRadius());
		if(posDist <= radDist)
		{
			Handler->SendMessage(0.0,0,3,MSG_ATK_AWR,NULL);
			m_player->EraseBall();
		}
	}

	if(m_player->isBallOn())
	{
		posDist = distFormula(m_player->getEballPos(),m_enemy4->getPosition());
		radDist = sumRadius(m_player->getEballRad(), m_enemy4->getRadius());
		if(posDist <= radDist)
		{
			Handler->SendMessage(0.0,0,4,MSG_ATK_AWR,NULL);
			m_player->EraseBall();
		}
	}



	if(m_player->nukeOn() && m_player->nukeCreate())
	{
		posDist = distFormula(m_player->getENukePos(),m_enemy1->getPosition());
		radDist = sumRadius(m_player->getENukeRad(), m_enemy1->getRadius());

		if(posDist <= radDist)
		{
			Handler->SendMessage(0.0,0,1,MSG_PRJCOLLIDE,NULL);
		}
	}

	if(m_player->nukeOn() && m_player->nukeCreate())
	{
		posDist = distFormula(m_player->getENukePos(),m_enemy2->getPosition());
		radDist = sumRadius(m_player->getENukeRad(), m_enemy2->getRadius());

		if(posDist <= radDist)
		{
			Handler->SendMessage(0.0,0,2,MSG_PRJCOLLIDE,NULL);
		}
	}
	
	if(m_player->nukeOn() && m_player->nukeCreate())
	{
		posDist = distFormula(m_player->getENukePos(),m_enemy3->getPosition());
		radDist = sumRadius(m_player->getENukeRad(), m_enemy3->getRadius());

		if(posDist <= radDist)
		{
			Handler->SendMessage(0.0,0,3,MSG_PRJCOLLIDE,NULL);
		}
	}

	if(m_player->nukeOn() && m_player->nukeCreate())
	{
		posDist = distFormula(m_player->getENukePos(),m_enemy4->getPosition());
		radDist = sumRadius(m_player->getENukeRad(), m_enemy4->getRadius());

		if(posDist <= radDist)
		{
			Handler->SendMessage(0.0,0,4,MSG_PRJCOLLIDE,NULL);
		}
	}

	if(m_player->nukeOn() && m_player->nukeCreate())
	{
		opTimer();
	}
}

void EntityManager::opTimer()
{
	d_Time = m_dt;

	alator += d_Time;

	if(alator > delay)
	{
		m_player->Nuke();

		alator = 0;
	}
}

void EntityManager::chargeOk()
{
	delta_t = m_dt;

	acum += delta_t;

	if(acum > dly_time)
	{
		m_player->setOK(1);

		acum = 0;
	}
	else
	{
		m_player->setOK(0);
	}
}

bool EntityManager::gameOver()
{
	bool game = false;

	if(m_player->getHP() <= 0)
	{
		MessageBox(NULL, "You Lost", "Game Over", MB_OK);
		game = true;
	}

	if(m_enemy1->getHP() <= 0 && 
	   m_enemy2->getHP() <= 0 &&
	   m_enemy3->getHP() <= 0 &&
	   m_enemy4->getHP() <= 0)
	{
		MessageBox(NULL, "You Won", "Game Over", MB_OK);
		game = true;
	}

	return game;
}

void EntityManager::shutDown()
{
	// Loop through all the objects in the vector and kill them off
	for (unsigned int i=0; i<objects.size(); i++)
	{
		if (objects[i])
		delete objects[i];
	}
}